package net.lastcoder.ifserver.session;

import net.lastcoder.ifserver.Constants;
import net.lastcoder.ifserver.Globals;
import net.lastcoder.ifserver.Server;
import net.lastcoder.ifserver.cache.Cache;
import net.lastcoder.ifserver.cache.CacheFactory;
import net.lastcoder.ifserver.module.BaseModule;
import net.lastcoder.ifserver.module.ModuleNames;
import net.lastcoder.ifserver.packet.Packet;
import net.lastcoder.ifserver.packet.SessionClosePacket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

/**会话管理器，一个模块。<br>
 * 如果需要监听会话事件，可以调用{@link #addSessionListener(SessionListener)}
 * auth: WenYF
 * date: 2016/9/29
 */
public class SessionManager extends BaseModule {
    private static final Logger Log = LoggerFactory.getLogger(SessionManager.class);

    private Cache<String, Session> sessions;
    private Cache<String, Session> adminSessions;

    private ArrayList<SessionListener> sessionListeners;

    @Override
    public void init() {
        sessions.setMaxLifetime(Globals.getXMLProperty("cache.usersessions.maxLifetime"
                , Constants.infinite));
        sessions.setMaxCacheSize(Globals.getXMLProperty("cache.usersessions.size"
                , Constants.infinite));
        adminSessions.setMaxLifetime(Globals.getXMLProperty("cache.adminsessions.maxLifetime"
                , Constants.infinite));
        adminSessions.setMaxCacheSize(Globals.getXMLProperty("cache.adminsessions.size"
                , Constants.infinite));
    }

    @Override
    public void reload() {
        SessionClosePacket packet = new SessionClosePacket(Packet.TYPE_SET);
        packet.setFromAddress(UlaID.fromAddress(Server.getInstance().getServerDomain()
                + "/" + UlaID.RESOURCE_SERVER));
        packet.setId(Packet.generateId());
        packet.setExtra(Constants.SHUTDOWN_DESC.getBytes());

        for (Session session : sessions.values()) {
            session.process(packet);
            session.close();
        }
        sessions.clear();

        init();
    }

    @Override
    public void destroy() {
        SessionClosePacket packet = new SessionClosePacket(Packet.TYPE_SET);
        packet.setFromAddress(UlaID.fromAddress(Server.getInstance().getServerDomain()
                + "/" + UlaID.RESOURCE_SERVER));
        packet.setId(Packet.generateId());
        packet.setExtra(Constants.SHUTDOWN_DESC.getBytes());

        for (Session session : new ArrayList<>(sessions.values())) {
            if (session != null) {
                session.process(packet);
                session.close();
            }
        }
        sessions.clear();

        for (Session session : new ArrayList<>(adminSessions.values())) {
            if (session != null) {
                session.process(packet);
                session.close();
            }
        }
        adminSessions.clear();
    }

    private static class SingletonHolder {
        static SessionManager instance = new SessionManager();
    }

    public static SessionManager getInstance() {
        return SingletonHolder.instance;
    }

    private SessionManager() {
        super(ModuleNames.SessionManager);
        sessions = CacheFactory.createCache("user sessions");
        adminSessions = CacheFactory.createCache("admin sessions");

        sessionListeners = new ArrayList<>();
    }

    /**
     * @param listener 添加一个会话监听器
     */
    public void addSessionListener(SessionListener listener) {
        sessionListeners.add(listener);
    }

    /**
     * @param listener 移除一个监听器，必须和添加成对出现
     */
    public void removeSessionListener(SessionListener listener) {
        sessionListeners.remove(listener);
    }

    /**
     * @return 得到所有会话监听器
     */
    protected Collection<SessionListener> getSessionListeners() {
       return Collections.unmodifiableList(sessionListeners);
    }

    /**一个用户名对应一个会话，不能1对N
     * @param username 用户名
     * @return
     */
    public Session getSession(String username) {
        return sessions.get(username);
    }

    /**
     * @param username
     * @return
     */
    protected Session removeSession(String username) {
        return sessions.remove(username);
    }

    protected void addSession(Session session) {
        Log.debug("add a session : " + session.getUsername());
        sessions.put(session.getUsername(), session);
    }

    /**
     * @return 得到所有管理员会话
     */
    public Collection<Session> getAdminSessions() {
        return adminSessions.values();
    }

    /**
     * @return 得到所有会话，不包括管理员
     */
    public Collection<Session> getSessions() {
        return sessions.values();
    }

    /**广播给所有用户
     * @param packet
     */
    public void broadcast(Packet packet) {
        packet.setFromAddress(Server.getInstance().getServerId());
        for (Session session : new ArrayList<>(sessions.values())) {
            if (session != null) {
                session.process(packet);
            }
        }
    }


    /**not impl, TODO it
     * @return always null
     */
    public Session getAdminSession() {
        // TODO
        return null;
    }

    public void addAdminSession(Session session) {
        adminSessions.put(session.getUsername(), session);
    }

    protected void removeAdminSession(String username) {
        adminSessions.remove(username);
    }

}
